/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1/commercial
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may use this file in compliance with the License.
 * Alternatively, if you can't copy with the License, namely if you do not
 * want to provide source code of your modifications to this file, you may
 * negotiate a commercial licence with the initial developer.
 * You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is COID.
 *
 * The Initial Developer of the Original Code is
 * PosAm.
 * Portions created by the Initial Developer are Copyright (C) 2003
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 * Brano Kemen
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

#ifndef __COID_H__
#define __COID_H__


#include "coid/comm/retcodes.h"
#include "coid/comm/version.h"
#include "coid/comm/password.h"
#include "coid/comm/net.h"
#include "coid/comm/binstream/inoutstream.h"

//included for convenience, not needed for core stuff
#include "coid/comm/binstream/stlstream.h"


////////////////////////////////////////////////////////////////////////////////
#define COID_VERSION        "1.4 (4.0)"


////////////////////////////////////////////////////////////////////////////////
#define net_fnc			/// net-enabled function
#define net_fnc_s		/// special function, e.g. accept_connect, accept_startup_params, ....

#define net_fnc_d		/// function that can by used only by direct calls
#define net_fnc_i		/// function that can by used only by inter-process calls
#define net_fnc_r		/// function that can by used only by network (remote) calls
				/// and all combinations: (net_fnc without postfixes means all of them)
#define net_fnc_di
#define net_fnc_id
#define net_fnc_dr
#define net_fnc_rd
#define net_fnc_ri
#define net_fnc_ir


#define net_in              /// input argument
#define net_out             /// output argument
#define net_inout           /// input-output argument
#define net_fetch           /// output argument without a temporary involved
#define net_remap(client_arg_type)	/// change argument type to 'client_arg_type' on client side (you should know what you are doing)
#define net_map(client_arg_type)	/// change argument type to 'client_arg_type' on client side (direct calls are really direct)
#define net_ptr             /// pointer value transfer
#define net_nolog
#define net_log             /// log arrays that are not logged by default (see documentation for more info)
#define net_nolock          /// do not lock object mutex for this method
#define net_meta            /// allow metastream access to function
#define net_account         /// account argument (comes with account_id reference (or ptr) in accept_connect[_shared] methods)
#define net_count(count)    /// insert this keyword before a pointer to transfer "count" items (== (count)*sizeof(type) bytes)
#define net_openservice(service_name)	/// you will receive connected client of another service ('service_name') on client side



namespace coid {

////////////////////////////////////////////////////////////////////////////////
struct StdProtocolMethod
{
    
    enum {
        CONNECT_CHAR                    = 0xb0,
        fCONNECT_BIGENDIAN              = 0x01,
        fCONNECT_64                     = 0x02,
    };

    enum {
        PING                            = 0xc0000000,
        CONNECT                         = 0xc0000001,

        DISCONNECT                      = 0xc0000003,
        DISCONNECT_AND_WAIT             = 0xc0000004,

        GET_INSTANCE_ADDRESS            = 0xc0000010,
        SET_CONN_TIMEOUT                = 0xc0000011,
    };

    struct ConnectFlags
    {
        enum {
            fUNIQUE_ACCESS              = 0x00000001,
            fCOMPRESS                   = 0x00000002,
            fENCRYPT                    = 0x00000004,
            fTUNNEL                     = 0x00000008,
            fWITHIN_CHANNEL             = 0x00000010,
            fPING_SERVER                = 0x00000100,

            xACCESS_MODE                = 0x00070000,
            fACCESS_MODE_DIRECT         = 0x00010000,
            fACCESS_MODE_INTERPROCESS   = 0x00020000,
            fACCESS_MODE_REMOTE         = 0x00040000,
        };

        static const char* get_access_mode_string( uint acm, char* buf4 )
        {
            buf4[0] = (acm & fACCESS_MODE_DIRECT) ? 'd' : '-';
            buf4[1] = (acm & fACCESS_MODE_INTERPROCESS) ? 'i' : '-';
            buf4[2] = (acm & fACCESS_MODE_REMOTE) ? 'r' : '-';
            buf4[3] = 0;
            return buf4;
        }
    };

    static const char* get_name( uint id )
    {
        switch(id)
        {
        case DISCONNECT:            return "$proto_disconnect";
        case DISCONNECT_AND_WAIT:   return "$proto_disconnect_and_wait";
        case GET_INSTANCE_ADDRESS:  return "$proto_get_instance_address";
        case SET_CONN_TIMEOUT:      return "$proto_set_conn_timeout";
        }
        return 0;
    }
};


typedef StdProtocolMethod::ConnectFlags		ConnectFlags;


////////////////////////////////////////////////////////////////////////////////
/// Standard dispatch methods
struct StdDispatchMethod
{
    enum {
        fNO_LOCK            = 0x01000000,   ///< don't lock mutex

        CONSTRUCTOR         = 0x80000001,   ///< create new instance
        POSTCONSTRUCTOR     = 0x8000000a,   ///< accept_startup_params
        PREDESTRUCTOR       = 0x80000002,   ///< notification that dependent server objects
                                            ///<  are about to be destroyed
        DESTRUCTOR          = fNO_LOCK | 0x80000003,   ///< destroy instance
        SPAWN               = fNO_LOCK | 0x80000004,   ///< call the spawn method (runs in separate thread)

        AUTHENTIFY          = 0x80000005,   ///< authentify primary connection
        AUTHENTIFY_SHARED   = 0x80000006,   ///< authentify shared connection
        AUTHENTIFY_AUTO     = 0x80000008,   ///< authentify automatic (global) instance

        CREATE_INTERFACE    = 0x80000010,   ///< authentify interface connection
        HANDLE_NET_LOOP     = fNO_LOCK | 0x80000011,   ///< process netSocket communication for special protocols

        COMMAND             = 0x80010000,   ///< command string
        ECHO                = 0x80010001,   ///< dump info
    };

    static const char* get_name( uint id )
    {
        switch(id)
        {
        case CONSTRUCTOR:           return "$constructor";
        case PREDESTRUCTOR:         return "$predestructor";
        case DESTRUCTOR:            return "$destructor";
        case SPAWN:                 return "$spawn";
        case AUTHENTIFY:            return "$authentify";
        case AUTHENTIFY_SHARED:     return "$authentify_shared";
        case AUTHENTIFY_AUTO:       return "$authentify_auto";
        case CREATE_INTERFACE:  return "$create_interface";
        case COMMAND:               return "$command";
        case ECHO:                  return "$echo";
        }
        return 0;
    }
};


////////////////////////////////////////////////////////////////////////////////
struct account_perm
{
    uint    _flags;

    enum {
        fPERM_MANAGE_ACCOUNTS           = 0x01,
    };

    account_perm() : _flags(0) { }


    friend binstream& operator << (binstream& bot, const account_perm& a)
    {   return bot << a._flags;    }

    friend binstream& operator >> (binstream& bot, account_perm& a)
    {   return bot >> a._flags;    }

    friend metastream& operator << (metastream& m, const account_perm& a)
    {
        MSTRUCT_OPEN(m, "account_perm");
        MM(m, "flags", a._flags );
        MSTRUCT_CLOSE(m);
    }
};

////////////////////////////////////////////////////////////////////////////////
struct account : account_id
{
    account_perm  _perm;


    friend binstream& operator << (binstream& bot, const account& a)
    {   return bot << (const account_id&)a << a._perm;    }

    friend binstream& operator >> (binstream& bot, account& a)
    {   return bot >> (account_id&)a >> a._perm;    }

    friend metastream& operator << (metastream& m, const account& a)
    {
        MSTRUCT_OPEN(m, "account");
        MMT(m, "base", account_id );
        MM(m, "permissions", a._perm );
        MSTRUCT_CLOSE(m);
    }
};

////////////////////////////////////////////////////////////////////////////////
struct COID_OPEN_SERVICE
{
private:
    bool swap;
    uint conn_mode;

public:
    binstreambuf br;
    binstreambuf bw;
    netAddress address;
    uint obj_id;

    COID_OPEN_SERVICE( bool swap_buffers=false, uint mode=ConnectFlags::xACCESS_MODE ) :
			swap(swap_buffers), conn_mode(mode), obj_id(UMAX32) {}

	uint get_conn_mode() const {return conn_mode;}

    friend binstream & operator << ( binstream & b, const COID_OPEN_SERVICE & x ) {
		if( x.swap ) return b << x.bw << x.conn_mode;
		return b << x.br << x.conn_mode;
    }
    friend binstream & operator >> ( binstream & b, COID_OPEN_SERVICE & x ) {
		if( x.swap ) return b >> x.br >> x.conn_mode;
		return b >> x.bw >> x.conn_mode;
    }
};

////////////////////////////////////////////////////////////////////////////////
struct NODE_ADDRESS
{
    uint _id;
    charstr _addr;

    NODE_ADDRESS ()
    {
        _id = UMAX32;
    }
    NODE_ADDRESS (ulong id, const char * addr) : _id(id), _addr(addr)
    {
    }

    friend binstream& operator << (binstream& out, const NODE_ADDRESS& a)
    {
        return out << a._addr << a._id;
    }

    friend binstream& operator >> (binstream& in, NODE_ADDRESS& a)
    {
        return in >> a._addr >> a._id;
    }
};

////////////////////////////////////////////////////////////////////////////////
struct COID_CLIENT_EXESTREAM_ARGS
{
	void * obj;
	uint id;
	COID_CLIENT_EXESTREAM_ARGS( void * o, uint i ) : obj(o), id(i) {}
};


} // namespace coid


#endif	// ! __COID_H__
